"""
策略抽象基类：定义策略接口规范
"""
import re
import pandas as pd
from typing import Dict
from abc import ABC
from datetime import date
from utils.logger import sys_logger

logger = sys_logger.getChild('Strategy')


class BaseStrategy(ABC):
	def __init__(self):
		"""
		初始化策略
		:param symbols: 监控的标的列表
		"""
		self._latest_data: Dict[str, Dict] = {}  # 各标的的最新股票数据
		self._history_data: Dict[str, pd.DataFrame] = {}  # 各标的的历史股价数据
		self._financial_data: Dict[str, pd.DataFrame] = {}  # 各标的的历史财务数据

		self.risk = None
		self.portfolio = None

	def bind(self, engine):
		self.engine = engine
		self.risk = self.engine.risk
		self.portfolio = self.engine.portfolio
		self.market = self.engine.market

	@property
	def current_date(self):
		return self._current_date

	@current_date.setter
	def current_date(self, date: date):
		self._current_date = date

	@staticmethod
	def _is_valid_symbol(symbol):
		"""
		验证股票代码格式合法性
		合法格式示例：600000.SH 或 000001.SZ

		验证规则：
		1. 格式：6位数字.交易所代码
		2. 沪市（.SH）：60/688/900开头
		3. 深市（.SZ）：00/30/200开头
		"""
		# 基础格式验证
		match = re.match(r"^(\d{6})\.([A-Za-z]{2})$", symbol)
		if not match:
			return False

		code, exchange = match.groups()
		exchange = exchange.upper()

		# 交易所代码验证
		if exchange not in ("SH", "SZ"):
			return False

		# 沪市代码规则验证
		if exchange == "SH":
			return any([
				code.startswith("60"),  # 主板
				code.startswith("688"),  # 科创板
				code.startswith("900")  # B股
			])

		# 深市代码规则验证
		if exchange == "SZ":
			return any([
				code.startswith("00"),  # 主板/中小板
				code.startswith("30"),  # 创业板
				code.startswith("200")  # B股
			])

		return False

	def load_latest_data(self, symbol: str, data: Dict) -> None:
		"""加载标的的最新股票数据
		:param symbol: 标的代码
		:param data: 标的最新股票数据
		"""
		self._latest_data[symbol] = data
		logger.debug("加载%s标的最新股票数据，最新股价 %.2f", symbol, data['lastPrice'])

	def load_history_k_day_data(self, symbol: str, data: pd.DataFrame) -> None:
		"""加载标的的历史股价数据
		:param symbol: 标的代码
		:param data: 包含DatetimeIndex的DataFrame（需有close字段）
		"""
		if not isinstance(data.index, pd.DatetimeIndex):
			raise ValueError("历史股价数据索引必须是DatetimeIndex")

		self._history_data[symbol] = data.sort_index(ascending=True)
		logger.debug("加载%s标的历史股价数据 | 时间范围: %s ~ %s | 数据量: %d",
		             symbol, data.index[0].date(), data.index[-1].date(), len(data))

	def load_financial_data(self, symbol: str, data: pd.DataFrame) -> None:
		"""加载标的的历史财务数据
		:param symbol: 标的代码
		:param data: 包含DatetimeIndex的DataFrame（需有close字段）
		"""
		if not isinstance(data.index, pd.DatetimeIndex):
			raise ValueError("历史财务数据索引必须是DatetimeIndex")

		self._financial_data[symbol] = data.sort_index(ascending=True)
		logger.debug("加载%s标的历史财务数据 | 时间范围: %s ~ %s | 数据量: %d",
		             symbol, data.index[0].date(), data.index[-1].date(), len(data))

	def pre_market(self) -> None:
		"""执行开盘前准备"""
		pass

	def on_open(self) -> None:
		"""执行开盘交易"""
		pass

	def on_trade(self) -> None:
		"""执行交易时段"""
		pass

	def on_close(self) -> None:
		"""执行收盘交易"""
		pass

	def post_market(self) -> None:
		"""执行收盘后记录"""
		pass
